package sqlwatcher

import (
	"encoding/binary"
	"fmt"
	"globalpedia-pc-backend/resource"
	"io"
	"log"
	"math"
	"net"
	"net/http"
	"strings"
	"sync"
	"time"

	"github.com/gin-gonic/gin"
)

const (
	MaxPacketSize = 1<<24 - 1
	HeaderSize    = 4
)



type preparedStatement struct {
	query      string
	params     int
	paramTypes []byte // 添加这个字段
}

type monitoredConnection struct {
	preparedStatements map[uint32]*preparedStatement
	stmtMutex          sync.RWMutex
}

func (mc *monitoredConnection) close() {
	mc.stmtMutex.Lock()
	defer mc.stmtMutex.Unlock()
}

func newMonitoredConnection() *monitoredConnection {
	return &monitoredConnection{
		preparedStatements: make(map[uint32]*preparedStatement),
	}
}

type monitoredReader struct {
	r          io.Reader
	direction  string
	packetChan chan []byte
	conn       *monitoredConnection
	buffer     []byte // 添加缓冲区
}

func newMonitoredReader(r io.Reader, direction string, conn *monitoredConnection) *monitoredReader {
	mr := &monitoredReader{
		r:          r,
		direction:  direction,
		packetChan: make(chan []byte, 1000),
		conn:       conn,
		buffer:     make([]byte, 0), // 初始化缓冲区
	}
	// 启动一个 Goroutine 来处理数据
	go mr.processData()
	return mr
}

func (mr *monitoredReader) close() {
	close(mr.packetChan)
}

func (mr *monitoredReader) Read(p []byte) (n int, err error) {
	n, err = mr.r.Read(p)
	if n > 0 {
		// 将读取到的数据发送到数据通道
		mr.packetChan <- append([]byte{}, p[:n]...)
		// mu.Lock()
		// defer mu.Unlock()
		// mr.buffer = append(mr.buffer, p[:n]...)
		// mr.parseBuffer()
	}
	return
}

// 新增的方法，用于异步处理数据
func (mr *monitoredReader) processData() {
	for data := range mr.packetChan {
		// 将读取到的数据添加到缓冲区
		mr.buffer = append(mr.buffer, data...)
		// 尝试解析缓冲区中的数据
		mr.parseBuffer()
	}
}

func (mr *monitoredReader) parseBuffer() {
	for {
		if len(mr.buffer) < 4 {
			// 缓冲区中的数据不足以解析出一个完整的数据包头部
			return
		}

		// 获取数据包长度
		length := int(mr.buffer[0]) | int(mr.buffer[1])<<8 | int(mr.buffer[2])<<16

		if len(mr.buffer) < length+4 {
			// 缓冲区中的数据不足以解析出一个完整的数据包
			return
		}

		// 解析完整的数据包
		packet := mr.buffer[4 : length+4]
		// fmt.Printf("解析数据包: 长度 %d, 方向 %s\n", length, mr.direction)
		mr.parsePacket(packet)

		// 移除已解析的数据包
		mr.buffer = mr.buffer[length+4:]
	}
}

// 添加一个新方法来处理MySQL服务器的Prepare响应
func (mr *monitoredReader) handlePrepareResponse(data []byte) {
	if len(data) < 12 {
		fmt.Println("Prepare响应数据不足")
		return
	}

	stmtID := binary.LittleEndian.Uint32(data[1:5])
	// columnCount := binary.LittleEndian.Uint16(data[5:7])
	paramCount := binary.LittleEndian.Uint16(data[7:9])

	mr.conn.stmtMutex.Lock()
	if stmt, ok := mr.conn.preparedStatements[stmtID]; ok {
		stmt.params = int(paramCount)
		// fmt.Printf("更新Prepare语句，ID: %d，参数数量: %d，列数: %d\n", stmtID, paramCount, columnCount)
	} else {
		// fmt.Printf("未找到对应的Prepare语句，ID: %d\n", stmtID)
	}
	mr.conn.stmtMutex.Unlock()
}

// 在parsePacket方法中添加对Prepare响应的处理
func (mr *monitoredReader) parsePacket(packet []byte) {
	if len(packet) < 1 {
		return
	}

	if mr.direction == "MySQL到代理" {
		// 处理MySQL服务器的响应
		if len(packet) >= 12 && packet[0] == 0x00 && isPrepareResponse(packet) {
			// 可能是Prepare语句的响应
			mr.handlePrepareResponse(packet)
		}
	} else if mr.direction == "客户端到代理" {
		switch packet[0] {
		case 0x03: // COM_QUERY
			query := string(packet[1:])
			addSql(query)
			fmt.Println("SQL:", query)
		case 0x16: // COM_STMT_PREPARE
			mr.handlePrepare(packet[1:])
		case 0x17: // COM_STMT_EXECUTE
			mr.handleExecute(packet[1:])
		}
	}
}

func (mr *monitoredReader) handlePrepare(data []byte) {
	sql := string(data)
	// fmt.Println("捕获的Prepare语句:", sql)
	// 生成一个新的 preparedStatement 并保存
	stmt := &preparedStatement{
		query:  sql,
		params: 0, // 初始化参数数量
	}
	stmtID := uint32(len(mr.conn.preparedStatements) + 1) // 简单生成一个 stmtID
	mr.conn.stmtMutex.Lock()
	mr.conn.preparedStatements[stmtID] = stmt
	mr.conn.stmtMutex.Unlock()
}

func (mr *monitoredReader) handleExecute(data []byte) {
	if len(data) < 5 {
		fmt.Println("无效的Execute包")
		return
	}
	stmtID := binary.LittleEndian.Uint32(data[0:4])
	mr.conn.stmtMutex.RLock()
	stmt, ok := mr.conn.preparedStatements[stmtID]
	mr.conn.stmtMutex.RUnlock()
	if !ok {
		fmt.Printf("未找到对应的Prepare语句，ID: %d\n", stmtID)
		return
	}

	// 解析参数
	params, newParamTypes, err := parseParams(data[5:], stmt)
	if err != nil {
		fmt.Println("解析参数失败:", err)
		return
	}

	// 如果收到新的参数类型，更新它们
	if newParamTypes != nil {
		mr.conn.stmtMutex.Lock()
		stmt.paramTypes = newParamTypes
		mr.conn.stmtMutex.Unlock()
	}

	// 打印重构的SQL
	reconstructedSQL := reconstructSQL(stmt.query, params)
	fmt.Println("SQL:", reconstructedSQL)
	addSql(reconstructedSQL)
}

func parseParams(data []byte, stmt *preparedStatement) ([]interface{}, []byte, error) {
	params := []interface{}{}
	pos := 0 // 从数据的开始位置开始解析

	// 跳过 flags (1 byte)
	// pos += 1

	// 跳过 iteration count (4 bytes)，通常为 1
	pos += 4

	if pos >= len(data) {
		return []interface{}{}, []byte{}, nil
		// return nil, nil, fmt.Errorf("数据不足以解析参数")
	}

	// 计算 NULL bitmap 的长度
	nullBitmapLen := (stmt.params + 7) / 8
	if pos+nullBitmapLen > len(data) {
		return nil, nil, fmt.Errorf("数据不足以解析NULL bitmap")
	}

	nullBitmap := data[pos : pos+nullBitmapLen]
	pos += nullBitmapLen

	// 检查是否有新的参数绑定
	var newParamTypes []byte
	if pos < len(data) && data[pos] == 0x01 {
		pos++ // 跳过 new params bound flag
		if pos+stmt.params*2 > len(data) {
			return nil, nil, fmt.Errorf("数据不足以解析新的参数类型")
		}
		newParamTypes = data[pos : pos+stmt.params*2]
		pos += stmt.params * 2
	}

	// 如果没有新的参数类型，使用之前保存的类型
	paramTypes := newParamTypes
	if paramTypes == nil {
		paramTypes = stmt.paramTypes
	}

	for i := 0; i < stmt.params; i++ {
		if nullBitmap[i/8]&(1<<(i%8)) != 0 {
			params = append(params, nil)
			continue
		}

		if pos >= len(data) {
			return nil, nil, fmt.Errorf("数据不足以解析参数值")
		}

		if len(paramTypes) <= i*2 {
			return nil, nil, fmt.Errorf("参数类型信息不足")
		}

		paramType := binary.LittleEndian.Uint16(paramTypes[i*2:])
		var param interface{}
		var err error

		switch paramType {
		case 0x01: // MYSQL_TYPE_TINY
			param, err = parseTiny(data, &pos)
		case 0x02: // MYSQL_TYPE_SHORT
			param, err = parseShort(data, &pos)
		case 0x03: // MYSQL_TYPE_LONG
			param, err = parseLong(data, &pos)
		case 0x04: // MYSQL_TYPE_FLOAT
			param, err = parseFloat(data, &pos)
		case 0x05: // MYSQL_TYPE_DOUBLE
			param, err = parseDouble(data, &pos)
		case 0x07: // MYSQL_TYPE_TIMESTAMP
			param, err = parseTimestamp(data, &pos)
		case 0x0a: // MYSQL_TYPE_DATE
			param, err = parseDate(data, &pos)
		case 0x0b: // MYSQL_TYPE_TIME
			param, err = parseTime(data, &pos)
		case 0x0e: // MYSQL_TYPE_DATETIME
			param, err = parseDatetime(data, &pos)
		case 0x08: // MYSQL_TYPE_LONGLONG
			param, err = parseLongLong(data, &pos)
		case 0x0f, 0xfe: // MYSQL_TYPE_VARCHAR, MYSQL_TYPE_VAR_STRING
			param, err = parseVarString(data, &pos)
		// 可以根据需要添加更多类型的解析
		default:
			return nil, nil, fmt.Errorf("不支持的参数类型: %d", paramType)
		}

		if err != nil {
			return nil, nil, err
		}
		params = append(params, param)
	}

	return params, newParamTypes, nil
}

func reconstructSQL(sql string, params []interface{}) string {
	parts := strings.Split(sql, "?")
	if len(parts) != len(params)+1 {
		return sql
	}

	var result strings.Builder
	for i, part := range parts[:len(parts)-1] {
		result.WriteString(part)
		result.WriteString(formatParam(params[i]))
	}
	result.WriteString(parts[len(parts)-1])
	return result.String()
}

func formatParam(param interface{}) string {
	switch v := param.(type) {
	case nil:
		return "NULL"
	case int, int8, int16, int32, int64, uint, uint8, uint16, uint32, uint64:
		return fmt.Sprintf("%d", v)
	case float32, float64:
		return fmt.Sprintf("%f", v)
	case string:
		return fmt.Sprintf("'%s'", strings.ReplaceAll(v, "'", "\\'"))
	default:
		return fmt.Sprintf("'%v'", v)
	}
}

type monitoredWriter struct {
	w         io.Writer
	direction string
	conn      *monitoredConnection
}

func newMonitoredWriter(w io.Writer, direction string, conn *monitoredConnection) *monitoredWriter {
	mw := &monitoredWriter{
		w:         w,
		direction: direction,
		conn:      conn,
	}
	return mw
}

func (mw *monitoredWriter) Write(p []byte) (n int, err error) {
	return mw.w.Write(p)
}

func Watch(port, targetAddress string) {
	listener, err := net.Listen("tcp", ":"+port)
	if err != nil {
		log.Fatal(err)
	}
	//defer listener.Close()
	log.Println("sql watcher start:", port)
	go func() {
		for {
			clientConn, err := listener.Accept()
			if err != nil {
				log.Println("Error accepting connection:", err)
				continue
			}
			go handleConnection(clientConn, targetAddress)
		}
	}()
}

func handleConnection(clientConn net.Conn, targetAddress string) {
	defer clientConn.Close()

	mysqlConn, err := net.Dial("tcp", targetAddress)
	if err != nil {
		log.Println("连接到MySQL时出错:", err)
		return
	}
	defer mysqlConn.Close()

	// 使用监视的读写器包装连接
	monitoredConn := newMonitoredConnection()

	clientReader := newMonitoredReader(clientConn, "客户端到代理", monitoredConn)
	mysqlReader := newMonitoredReader(mysqlConn, "MySQL到代理", monitoredConn)

	monitoredClientConn := struct {
		io.Reader
		io.Writer
	}{
		Reader: clientReader,
		Writer: newMonitoredWriter(clientConn, "代理到客户端", monitoredConn),
	}

	monitoredMysqlConn := struct {
		io.Reader
		io.Writer
	}{
		Reader: mysqlReader,
		Writer: newMonitoredWriter(mysqlConn, "代理到MySQL", monitoredConn),
	}

	done := make(chan struct{})

	go func() {
		_, err := io.Copy(monitoredClientConn, monitoredMysqlConn)
		if err != nil {
			// log.Println("复制数据时出错:", err)
			done <- struct{}{}
		}
	}()
	go func() {
		_, err := io.Copy(monitoredMysqlConn, monitoredClientConn)
		if err != nil {
			// log.Println("复制数据时出错:", err)
			done <- struct{}{}
		}
	}()

	// go func() {
	// 	var input string
	// 	fmt.Scanln(&input)
	// 	close(done)
	// }()

	<-done

	clientReader.close()
	mysqlReader.close()
}

func parseTiny(data []byte, pos *int) (int8, error) {
	if *pos >= len(data) {
		return 0, fmt.Errorf("数据不足以解析TINY")
	}
	val := int8(data[*pos])
	*pos++
	return val, nil
}

func parseShort(data []byte, pos *int) (int16, error) {
	if *pos+2 > len(data) {
		return 0, fmt.Errorf("数据不足以解析SHORT")
	}
	val := int16(binary.LittleEndian.Uint16(data[*pos : *pos+2]))
	*pos += 2
	return val, nil
}

func parseLong(data []byte, pos *int) (int32, error) {
	if *pos+4 > len(data) {
		return 0, fmt.Errorf("数据不足以解析LONG")
	}
	val := int32(binary.LittleEndian.Uint32(data[*pos : *pos+4]))
	*pos += 4
	return val, nil
}

func parseFloat(data []byte, pos *int) (float32, error) {
	if *pos+4 > len(data) {
		return 0, fmt.Errorf("数据不足以解析FLOAT")
	}
	bits := binary.LittleEndian.Uint32(data[*pos : *pos+4])
	*pos += 4
	return math.Float32frombits(bits), nil
}

func parseDouble(data []byte, pos *int) (float64, error) {
	if *pos+8 > len(data) {
		return 0, fmt.Errorf("数据不足以解析DOUBLE")
	}
	bits := binary.LittleEndian.Uint64(data[*pos : *pos+8])
	*pos += 8
	return math.Float64frombits(bits), nil
}

func parseLongLong(data []byte, pos *int) (int64, error) {
	if *pos+8 > len(data) {
		return 0, fmt.Errorf("数据不足以解析LONGLONG")
	}
	val := int64(binary.LittleEndian.Uint64(data[*pos : *pos+8]))
	*pos += 8
	return val, nil
}

func parseVarString(data []byte, pos *int) (string, error) {
	if *pos+1 > len(data) {
		return "", fmt.Errorf("数据不足以解析VAR_STRING长度")
	}
	length := int(data[*pos])
	*pos++

	if *pos+length > len(data) {
		return "", fmt.Errorf("数据不足以解析VAR_STRING内容")
	}
	val := string(data[*pos : *pos+length])
	*pos += length
	return val, nil
}

func parseDate(data []byte, pos *int) (string, error) {
	if *pos+3 > len(data) {
		return "", fmt.Errorf("数据不足以解析DATE")
	}
	year := int(binary.LittleEndian.Uint16(data[*pos : *pos+2]))
	month := int(data[*pos+2])
	day := int(data[*pos+3])
	*pos += 4
	return fmt.Sprintf("%04d-%02d-%02d", year, month, day), nil
}

func parseTime(data []byte, pos *int) (string, error) {
	if *pos+3 > len(data) {
		return "", fmt.Errorf("数据不足以解析TIME")
	}
	negative := data[*pos]&0x80 != 0
	days := int(binary.LittleEndian.Uint32(data[*pos : *pos+4]))
	hours := int(data[*pos+4])
	minutes := int(data[*pos+5])
	seconds := int(data[*pos+6])
	*pos += 7
	sign := ""
	if negative {
		sign = "-"
	}
	return fmt.Sprintf("%s%d %02d:%02d:%02d", sign, days, hours, minutes, seconds), nil
}

func parseDatetime(data []byte, pos *int) (string, error) {
	if *pos+8 > len(data) {
		return "", fmt.Errorf("数据不足以解析DATETIME")
	}
	date, err := parseDate(data, pos)
	if err != nil {
		return "", err
	}
	time, err := parseTime(data, pos)
	if err != nil {
		return "", err
	}
	return fmt.Sprintf("%s %s", date, time), nil
}

func parseTimestamp(data []byte, pos *int) (string, error) {
	if *pos+4 > len(data) {
		return "", fmt.Errorf("数据不足以解析TIMESTAMP")
	}
	unixTime := int64(binary.LittleEndian.Uint32(data[*pos : *pos+4]))
	*pos += 4
	t := time.Unix(unixTime, 0).UTC()
	return t.Format("2006-01-02 15:04:05"), nil
}

func isPrepareResponse(packet []byte) bool {
	// Prepare响应的特征：
	// 1. 第一个字节是0x00（OK包）
	// 2. 接下来是4字节的statement_id
	// 3. 然后是2字节的列数
	// 4. 再然后是2字节的参数数
	// 5. 1字节的填充（0x00）
	// 6. 2字节的警告数

	if len(packet) < 12 {
		return false
	}

	// 检查填充字节是否为0x00
	if packet[9] != 0x00 {
		return false
	}

	// 其他字段应该包含有效的值
	statementID := binary.LittleEndian.Uint32(packet[1:5])
	columnCount := binary.LittleEndian.Uint16(packet[5:7])
	paramCount := binary.LittleEndian.Uint16(packet[7:9])

	// statement_id 应该大于0，列数和参数数可以为0
	return statementID > 0 && (columnCount > 0 || paramCount > 0)
}
